/***************************************************************************************************
 *Copyright(C),2010-2016,Sumscope
 *FileName	:  MacroIndexDict.cpp
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2017/04/19
 *Desc		:  宏观指标字典的数据存储
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#include "MacroIndexDict.h"

#include <core/dicttool/BondMacroIndex.h>
#include <core/time/time.h>

#define RTL_FIELD_SIZE(type, field) (sizeof(((type*)0)->field))
#ifndef max
#define max(a, b) ((a) > (b)) ? (a) : (b)
#endif

/*
        该字典 的保存与其他的字典不一样
        全部更新包完毕后才更新文件,其他的每个更新包结束后就立马更新文件
*/
typedef qb::base::HighResTime HighResTime;
namespace qb {
namespace ht {
// 与旧map<string,set<MACRO_INDEX>>相比:
// 时间对比:414695 us  37474 us  倍数 : 11.07 "
// 内存对比 : 6573784   2560192   倍数 : 2.57 "
// 实现机制:
// 将每个种类的每年宏观指标全都保存在一个长度为366的数组中
// 数组索引即可计算出日期,第一天是1月1日索引为0,第二天是1月2日索引为1
// 快在哪里?
// 1.MacroIndex* GetOrCreateIndex(const char*
// name)接口中使用了缓存,无需查表,直接稍作检验
//		原因在于相同指标的数据往往多个连续出现,这样只需要查表一次即可
// 2.将DayIndex转化为日期,使用预先计算的索引表,直接获取,见IndexDateMap
// 3.写数据的时候,直接通过DayIndex来写入数据,无需遍历查找等复杂操作
class MacroIndexManager {
 public:
  enum {
    DAY_COUNT = 366,  // 一年最多366天
    DATE_MIN = 101,   // 一年的第一天,1月1日
    DATE_MAX = 1231   // 一年最后一天,12月31日
  };
  typedef unsigned int DateType;  // 8位整数编码,日期,如:20171205
  typedef unsigned int
      DayIndex;  // 每日在一年中的编号,取值范围[0,365],0表示1月1日
  typedef unsigned int YearType;  // 年份,如 2017
  typedef unsigned char uchar;
  typedef unsigned short ushort;

 protected:
  struct MonthAndDay {
    uchar month, day;
  };
  class IndexDateMap {
    MonthAndDay m_days[DAY_COUNT];  // 从DayIndex到月日的映射,闰年或者非闰年
   public:
    IndexDateMap(bool leap) {
      uchar monthdays[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
      if (!leap) {
        monthdays[1] = 28;
      }
      int index = 0;
      memset(m_days, 0, sizeof(MonthAndDay) * DAY_COUNT);
      for (uchar m = 0; m < 12; m++) {
        uchar days = monthdays[m];
        for (uchar d = 0; d < days; d++, index++) {
          m_days[index].month = m + 1;
          m_days[index].day = d + 1;
        }
      }
    }
    DateType GetDate(DayIndex index) {
      return ((DateType)m_days[index].month) * 100 + m_days[index].day;
    }
  };
  class DateIndexMap {
    ushort m_days[DATE_MAX + 1];  // 1232个查找表
   public:
    DateIndexMap(bool leap) {
      memset(m_days, 0xff, (DATE_MAX + 1) * sizeof(ushort));
      uchar monthdays[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
      if (!leap) {
        monthdays[1] = 28;
      }
      ushort index = 0;  // DadyIndex
      for (int m = 1; m <= 12; m++) {
        uchar days = monthdays[m - 1];
        int base = m * 100;
        for (uchar d = 1; d <= days; d++) {
          m_days[base + d] = index++;  // 根据月日来查找DayIndex
        }
      }
    }
    DayIndex GetDayIndex(DateType monthDate) {
      DayIndex index = 0xffff;
      if (monthDate >= 0 && monthDate <= DATE_MAX) {
        index = m_days[monthDate];
      }
      return index;
    }
  };
  class Util {
   public:
    static bool IsLeapYear(int year) {
      return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
    }
    static DayIndex GetMaxDayIndex(YearType year) {
      return IsLeapYear(year) ? (DAY_COUNT - 1) : (DAY_COUNT - 2);
      // 如果是闰年,返回366-1,否则返回365-1
    }
    static DateType GetDateType(YearType year, DayIndex day) {
      static IndexDateMap leapyear(true);
      static IndexDateMap noryear(false);
      DateType date =
          IsLeapYear(year) ? leapyear.GetDate(day) : noryear.GetDate(day);
      date += year * 10000;
      return date;
    }
    static YearType GetDateYear(DateType date, DayIndex& index) {
      static DateIndexMap leapyear_dim(true);
      static DateIndexMap noryear_dim(false);
      static int monthdays[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
      YearType year = date / 10000;
      DateType mday = date - year * 10000;
      index = IsLeapYear(year) ? leapyear_dim.GetDayIndex(mday)
                               : noryear_dim.GetDayIndex(mday);
      return year;

      int month = mday / 100;
      int day = date - year * 10000 - month * 100;
      for (int i = 0; i < month - 1; i++) {
        day += monthdays[i];
      }
      if (month > 2 && !IsLeapYear(year)) day--;
      index = day - 1;
      return year;
    }
  };

 public:
  class MacroIndex;
  class YearValueArray {
    YearType m_year;
    double m_values[DAY_COUNT];

   public:
    YearValueArray(YearType year) : m_year(year) {
      for (int i = 0; i < DAY_COUNT; i++) m_values[i] = -1.0;
    }
    YearType GetYear() const { return m_year; }
    void SetValue(double value, DayIndex start, DayIndex end) {
      for (DayIndex i = start; i <= end; i++) m_values[i] = value;
    }
    bool GetValue(DayIndex& day, double& value, DateType& start,
                  DateType& end) {
      // 从day开始,获取下一个可用的值
      // 如果值连续相同,设置日期范围
      if (day >= DAY_COUNT) return false;
      for (; day < DAY_COUNT; day++) {
        if (m_values[day] >= 0.0) break;
      }
      if (day >= DAY_COUNT) return false;
      value = m_values[day++];
      end = start = Util::GetDateType(m_year, day - 1);
      for (; day < DAY_COUNT; day++) {
        if (m_values[day] != value) break;
        end = Util::GetDateType(m_year, day);
      }
      return true;
    }
  };
  struct ValueInfo {
    DateType start, end;
    double value;
  };
  class MacroIndex : public std::map<YearType, YearValueArray*> {
    std::string m_name;

   public:
    MacroIndex(const std::string& name) : m_name(name) {}
    ~MacroIndex() {
      for (iterator it = begin(); it != end(); ++it) {
        YearValueArray* varray = it->second;
        if (varray) delete varray;
      }
      clear();
    }
    const std::string& GetName() const { return m_name; }
    YearValueArray* GetValueArray(YearType year) {
      iterator it = find(year);
      if (it != end()) return it->second;
      YearValueArray* varray = new YearValueArray(year);
      insert(value_type(year, varray));
      return varray;
    }
    int GetCount() const {
      ValueInfo last = {0}, cur = {0};
      last.value = -1.0;
      int ncount = 0;
      for (const_iterator it = cbegin(); it != cend(); ++it) {
        YearValueArray* yva = it->second;
        DayIndex day = 0;
        while (yva->GetValue(day, cur.value, cur.start, cur.end)) {
          if (last.value == cur.value && (cur.start % 10000 == DATE_MIN) &&
              (last.end % 10000 == DATE_MAX)) {
            last.end = cur.end;
          } else {
            if (last.value >= 0 && last.start != 0 && last.end != 0) ncount++;
            last = cur;
          }
        }
      }
      if (last.value >= 0 && last.start != 0 && last.end != 0) ncount++;
      return ncount;
    }
    bool GetValues(std::vector<ValueInfo>& values) {
      ValueInfo last = {0}, cur = {0};
      last.value = -1.0;
      values.clear();
      values.reserve(size() * 255);  // 每年有255个工作日
      for (iterator it = begin(); it != end(); ++it) {
        YearValueArray* yva = it->second;
        DayIndex day = 0;
        while (yva->GetValue(day, cur.value, cur.start, cur.end)) {
          if (last.value == cur.value && (cur.start % 10000 == 101) &&
              (last.end % 10000 == 1231)) {
            last.end = cur.end;
          } else {
            if (last.value >= 0 && last.start != 0 && last.end != 0)
              values.push_back(last);
            last = cur;
          }
        }
      }
      if (last.value >= 0 && last.start != 0 && last.end != 0)
        values.push_back(last);
      return values.size() > 0;
    }
  };

 protected:
  typedef std::map<std::string, MacroIndex*> MacroIndexMap;
  MacroIndexMap m_index_map;
  int m_total_count;
  bool m_count_dirty;
  MacroIndex* m_last;

 public:
  MacroIndexManager() : m_last(NULL), m_count_dirty(true), m_total_count(0) {}
  ~MacroIndexManager() {
    MacroIndexMap::iterator it = m_index_map.begin();
    for (; it != m_index_map.end(); ++it) {
      MacroIndex* mi = it->second;
      if (mi) delete mi;
    }
    m_index_map.clear();
  }
  int GetMemoryBytes() {
    int bytes = 0;
    for (MacroIndexMap::iterator it = m_index_map.begin();
         it != m_index_map.end(); ++it) {
      MacroIndex* mi = it->second;
      bytes += mi->size() * sizeof(YearValueArray);
    }
    return bytes;
  }
  int GetCount() {
    // 每次SetValue都会导致m_count_dirty为true,会导致下面代码重新计算
    if (m_count_dirty) {
      int ncount = 0;
      HighResTime timer;
      MacroIndexMap::const_iterator it = m_index_map.begin();
      for (; it != m_index_map.end(); ++it) {
        MacroIndex* mi = it->second;
        ncount += mi->GetCount();
      }
      m_total_count = ncount;
      m_count_dirty = false;
    }
    return m_total_count;
  }
  void GetAllArrays(std::vector<MacroIndex*>& arrays) {
    arrays.clear();
    arrays.reserve(GetArrayCount());
    MacroIndexMap::iterator it = m_index_map.begin();
    for (; it != m_index_map.end(); ++it) {
      MacroIndex* mi = it->second;
      arrays.push_back(mi);
    }
  }
  int GetArrayCount() const {
    int ncount = 0;
    MacroIndexMap::const_iterator it = m_index_map.begin();
    for (; it != m_index_map.end(); ++it) {
      ncount += it->second->size();
    }
    return ncount;
  }
  bool SetValue(const char* name, double value, DateType date, DateType end,
                bool del) {
    // 如果检测到日期格式date和end出现错误,就返回false
    // 否则返回true
    m_count_dirty = true;
    MacroIndex* mindex = GetOrCreateIndex(name);
    YearType y1, y2;
    DayIndex d1, d2;
    y1 = Util::GetDateYear(date, d1);
    if (date == end) {
      y2 = y1, d2 = d1;
    } else
      y2 = Util::GetDateYear(end, d2);
    if (d1 >= DAY_COUNT || d2 >= DAY_COUNT) {
      return false;
    }
    DateType date1 = Util::GetDateType(y1, d1);
    DateType date2 = Util::GetDateType(y2, d2);

    if (y1 == y2) {
      YearValueArray* yva = mindex->GetValueArray(y1);
      yva->SetValue(del ? -1.0 : value, d1, d2);
    } else {
      for (YearType y = y1; y <= y2; y++) {
        YearValueArray* yva = mindex->GetValueArray(y);
        DayIndex iStart = y == y1 ? d1 : 0;
        DayIndex iEnd = y == y2 ? d2 : Util::GetMaxDayIndex(y);
        yva->SetValue(del ? -1.0 : value, iStart, iEnd);
      }
    }
    return true;
  }

 protected:
  MacroIndex* GetOrCreateIndex(const char* name) {
    if (m_last && strcmp(name, m_last->GetName().c_str()) == 0) return m_last;
    MacroIndexMap::iterator it = m_index_map.find(name);
    if (it != m_index_map.end()) {
      m_last = it->second;
    } else {
      m_last = new MacroIndex(name);
      m_index_map[name] = m_last;
    }
    return m_last;
  }
};

//////////////////////////////////////////////////////////////////////////
MacroIndexDict::MacroIndexDict() : m_md5(""), m_updateid(0), m_benchlog(false) {
  m_times[0] = m_times[1] = 0.0;
  // m_benchlog = true;
  m_macroindexv2 = new MacroIndexManager();
}
MacroIndexDict::~MacroIndexDict() {
  if (m_macroindexv2) delete m_macroindexv2;
  m_macroindexv2 = NULL;
}
void MacroIndexDict::UpdateState(const char* md5, int updateid) {
  m_md5 = md5;
  m_updateid = updateid;
}

int MacroIndexDict::GetCount() const {
  // 计算总共有多少条宏观指标数据
  if (m_macroindexv2 == NULL) return 0;

  return m_macroindexv2->GetCount();
  // 旧版实现
  // int count = 0;
  // for (MacroIndexSetMap::const_iterator it = m_macroindex.begin(); it !=
  // m_macroindex.end(); ++it)
  //{
  //	count += it->second.size();
  //}
  // return count;
}

bool MacroIndexDict::UpdateElement(const DICT_MACRO_INDEX& elemval) {
  // 此函数可能会有11w以上次数的调用
  double d1 = 0.0, d2 = 0.0;
  HighResTime timer;
  if (m_benchlog) {
    MACRO_INDEX ele = {0};
    memcpy(ele.Code, elemval.Code, RTL_FIELD_SIZE(DICT_MACRO_INDEX, Code));
    ele.Value = elemval.Value;
    ele.Date = elemval.Date;
    ele.EndDate = elemval.EndDate;
    ele.Flag = elemval.Flag;
    ele.Sequence = elemval.Sequence;

    UpdateMacroElement(m_macroindex[elemval.Code], ele);
  }
  d1 = timer.elapsed();
  timer = HighResTime();
  bool suc = m_macroindexv2->SetValue(elemval.Code, elemval.Value, elemval.Date,
                                      elemval.EndDate, elemval.Flag == 'D');
  d2 = timer.elapsed();
  m_times[0] += d1;
  m_times[1] += d2;
  return suc;
}

int MacroIndexDict::CalcDateDiff(int datestart, int dateend) {
  struct tm t1, t2;
  memset(&t1, 0, sizeof(tm));
  t1.tm_year = datestart / 10000 - 1900;
  datestart = datestart - datestart / 10000 * 10000;
  t1.tm_mon = datestart / 100 - 1;
  datestart = datestart - datestart / 100 * 100;
  t1.tm_mday = datestart;

  memset(&t2, 0, sizeof(tm));
  t2.tm_year = dateend / 10000 - 1900;
  dateend = dateend - dateend / 10000 * 10000;
  t2.tm_mon = dateend / 100 - 1;
  dateend = dateend - dateend / 100 * 100;
  t2.tm_mday = dateend;

  int ret = static_cast<int>(difftime(mktime(&t2), mktime(&t1)));
  ret = ret / 86400;

  return ret;
}

int MacroIndexDict::DateAdd(int date, int delta) {
  struct tm t1;
  memset(&t1, 0, sizeof(tm));
  t1.tm_year = date / 10000 - 1900;
  date = date - date / 10000 * 10000;
  t1.tm_mon = date / 100 - 1;
  date = date - date / 100 * 100;
  t1.tm_mday = date;
  time_t time1 = mktime(&t1);
  time1 = time1 + 86400 * delta;
  tm p = qb::base::time2tm(time1);
  char buffer[16] = {0};
  FMTBUF(buffer, "%04d%02d%02d", p.tm_year + 1900, p.tm_mon + 1, p.tm_mday);

  return atoi(buffer);
}

void MacroIndexDict::UpdateMacroElement(MacroIndexSet& objset,
                                        MACRO_INDEX& elemval) {
  // 原始逻辑,一行都没有动
  //	TRACE("%f|%d|%d\n",elemval.Value,elemval.Date,elemval.EndDate);
  if (objset.size() == 0 ||
      CalcDateDiff(elemval.EndDate, objset.begin()->Date) >= 2 ||
      CalcDateDiff(objset.rbegin()->EndDate, elemval.Date) >= 2) {
    if (elemval.Flag != 'D') objset.insert(elemval);
    return;
  }
  if (elemval.Date <= objset.begin()->Date &&
      elemval.EndDate >= objset.rbegin()->EndDate) {
    objset.clear();
    if (elemval.Flag != 'D') objset.insert(elemval);
    return;
  }

  Element tail_before = {0}, tail_after = {0};
  Element head_before = {0}, head_after = {0};
  std::set<Element>::iterator split_it;
  // locate lower bound start pos
  std::set<Element>::iterator lowbound_it = objset.lower_bound(elemval);
  if (objset.begin()->Date >= elemval.Date) {
    // this is the first element,low bound is the beginning of the set
  } else {
    --lowbound_it;
    if (elemval.Value == lowbound_it->Value) {
      if (CalcDateDiff(lowbound_it->EndDate, elemval.Date) >= 2) {
        ++lowbound_it;
      } else {
        if (elemval.Flag != 'D') {
          elemval.Date = lowbound_it->Date;
        } else {
          if (elemval.Date > lowbound_it->EndDate) {
            ++lowbound_it;
          } else {  // split header, here lowbound could not be a dot time
            split_it = lowbound_it;
            head_before.Value = split_it->Value;
            FIELDCOPY(head_before.Code, split_it->Code);
            head_before.Date = split_it->Date;
            head_before.EndDate = DateAdd(elemval.Date, -1);

            head_after.Value = split_it->Value;
            FIELDCOPY(head_after.Code, split_it->Code);
            head_after.Date = elemval.Date;
            head_after.EndDate = split_it->EndDate;

            objset.erase(split_it);
            objset.insert(head_before);
            objset.insert(head_after);
            lowbound_it = objset.lower_bound(head_after);
          }
        }
      }
    } else {
      if (elemval.Date > lowbound_it->EndDate) {
        ++lowbound_it;
      } else {  // split header, here lowbound could not be a dot time
        split_it = lowbound_it;
        head_before.Value = split_it->Value;
        FIELDCOPY(head_before.Code, split_it->Code);
        head_before.Date = split_it->Date;
        head_before.EndDate = DateAdd(elemval.Date, -1);

        head_after.Value = split_it->Value;
        FIELDCOPY(head_after.Code, split_it->Code);
        head_after.Date = elemval.Date;
        head_after.EndDate = split_it->EndDate;

        objset.erase(split_it);
        objset.insert(head_before);
        objset.insert(head_after);
        lowbound_it = objset.lower_bound(head_after);
      }
    }
  }

  // locate upper bound start pos
  Element upbound = {0};
  upbound.Date = elemval.EndDate;
  std::set<Element>::iterator upbound_it = objset.lower_bound(upbound);
  if (upbound_it == objset.end()) {  // EndDate > end().Date
    split_it = objset.end();
    --split_it;
    if (split_it->Value == elemval.Value) {
      elemval.EndDate = max(elemval.EndDate, split_it->EndDate);
    } else {
      if (elemval.EndDate >= split_it->EndDate) {
        // ok
      } else {  // here split could not be a dot time
        tail_before.Value = split_it->Value;
        FIELDCOPY(tail_before.Code, split_it->Code);
        tail_before.Date = split_it->Date;
        tail_before.EndDate = elemval.EndDate;

        tail_after.Value = split_it->Value;
        FIELDCOPY(tail_after.Code, split_it->Code);
        tail_after.Date = DateAdd(elemval.EndDate, 1);
        tail_after.EndDate = split_it->EndDate;

        if (lowbound_it != split_it) objset.erase(split_it);
        objset.insert(tail_before);
        objset.insert(tail_after);
        upbound_it = objset.lower_bound(tail_after);
      }
    }
  } else if (upbound_it == objset.begin()) {  // EndDate <= begin().Date
    if (upbound_it->Value == elemval.Value) {
      if (elemval.Flag != 'D') {
        elemval.EndDate = max(elemval.EndDate, upbound_it->EndDate);
        ++upbound_it;
      } else {
        if (elemval.EndDate < objset.begin()->Date) {
          // ok
        } else {  // EndDate = begin.Date
          split_it = objset.begin();
          if (split_it->Date == split_it->EndDate)
            ++upbound_it;
          else {
            // split begin
            tail_after.Value = split_it->Value;
            FIELDCOPY(tail_after.Code, split_it->Code);
            tail_after.Date = DateAdd(elemval.EndDate, 1);
            tail_after.EndDate = split_it->EndDate;
            objset.erase(split_it);
            objset.insert(tail_after);
            lowbound_it = upbound_it = objset.begin();
          }
        }
      }
    } else {
      split_it = upbound_it;
      if (elemval.EndDate < split_it->Date) {
        // ok
      } else {
        if (split_it->Date == split_it->EndDate) {
          ++upbound_it;
          if (upbound_it != objset.end()) {
            if (elemval.Flag != 'D') {
              if ((elemval.Value == upbound_it->Value) &&
                  (CalcDateDiff(elemval.EndDate, upbound_it->Date) <= 1)) {
                elemval.EndDate = upbound_it->EndDate;
                ++upbound_it;
              }
            }
          }
        } else {
          head_after.Value = split_it->Value;
          FIELDCOPY(head_after.Code, split_it->Code);
          head_after.Date = DateAdd(elemval.EndDate, 1);
          head_after.EndDate = split_it->EndDate;

          if (lowbound_it != upbound_it) objset.erase(split_it);
          objset.insert(head_after);
          upbound_it = objset.lower_bound(head_after);
        }
      }
    }
  } else {
    split_it = --upbound_it;
    ++upbound_it;
    // EndDate<=upbound_it
    if (elemval.Value == split_it->Value) {
      if (elemval.EndDate == upbound_it->Date) {
        if (elemval.Value == upbound_it->Value) {
          if (elemval.Flag != 'D') {
            elemval.EndDate = upbound_it->EndDate;
            ++upbound_it;
          } else {  // split upbound_it
            ++split_it;
            if (split_it->Date == split_it->EndDate) {
              ++upbound_it;
            } else {
              tail_before.Value = split_it->Value;
              FIELDCOPY(tail_before.Code, split_it->Code);
              tail_before.Date = split_it->Date;
              tail_before.EndDate = elemval.EndDate;

              tail_after.Value = split_it->Value;
              FIELDCOPY(tail_after.Code, split_it->Code);
              tail_after.Date = DateAdd(elemval.EndDate, 1);
              tail_after.EndDate = split_it->EndDate;

              objset.insert(tail_before);
              objset.insert(tail_after);
              upbound_it = objset.lower_bound(tail_after);
            }
          }
        } else {
          if (upbound_it->Date == upbound_it->EndDate) {
            if (lowbound_it != upbound_it) {
              objset.erase(upbound_it);
              upbound_it = objset.lower_bound(upbound);
            } else {
              if (upbound_it != objset.end()) ++upbound_it;
            }
          } else {
            tail_after.Value = upbound_it->Value;
            FIELDCOPY(tail_after.Code, upbound_it->Code);
            tail_after.Date = DateAdd(elemval.EndDate, 1);
            tail_after.EndDate = upbound_it->EndDate;
            if (lowbound_it != upbound_it) objset.erase(upbound_it);
            objset.insert(tail_after);
            upbound_it = objset.lower_bound(tail_after);
          }
        }
      } else {
        if (elemval.EndDate >= split_it->EndDate) {
          if (1 == CalcDateDiff(elemval.EndDate, upbound_it->Date)) {
            if (elemval.Flag != 'D') {
              if (elemval.Value == upbound_it->Value) {
                elemval.EndDate = upbound_it->EndDate;
                ++upbound_it;
              }
            }
          }
        } else {  // here split could not be a dot time
          elemval.EndDate = split_it->EndDate;
        }
      }
    } else {  // not same value
      if (elemval.EndDate == upbound_it->Date) {
        if (elemval.Value == upbound_it->Value) {
          if (elemval.Flag != 'D') {
            elemval.EndDate = upbound_it->EndDate;
            ++upbound_it;
          } else {
            // split upbound_it
            if (upbound_it->Date == upbound_it->EndDate) {
              ++upbound_it;
            } else {
              tail_after.Value = upbound_it->Value;
              tail_after.Date = DateAdd(upbound_it->Date, 1);
              tail_after.EndDate = upbound_it->EndDate;
              FIELDCOPY(tail_after.Code, upbound_it->Code);
              if (lowbound_it != upbound_it) objset.erase(upbound_it);
              objset.insert(tail_after);
              upbound_it = objset.lower_bound(tail_after);
            }
          }
        } else {
          if (upbound_it->Date == upbound_it->EndDate) {
            if (lowbound_it != upbound_it) {
              objset.erase(upbound_it);
              upbound_it = objset.lower_bound(upbound);
            } else {
              if (upbound_it != objset.end()) {
                ++upbound_it;
                if (elemval.Flag != 'D') {
                  if (upbound_it != objset.end()) {
                    if ((upbound_it->Value == elemval.Value) &&
                        (CalcDateDiff(elemval.EndDate, upbound_it->Date) <=
                         1)) {
                      elemval.EndDate = upbound_it->EndDate;
                      ++upbound_it;
                    }
                  }
                }
              }
            }
          } else {
            tail_after.Value = upbound_it->Value;
            FIELDCOPY(tail_after.Code, upbound_it->Code);
            tail_after.Date = DateAdd(elemval.EndDate, 1);
            tail_after.EndDate = upbound_it->EndDate;
            if (lowbound_it != upbound_it) objset.erase(upbound_it);
            objset.insert(tail_after);
            upbound_it = objset.lower_bound(tail_after);
          }
        }
      } else {
        if (elemval.EndDate >= split_it->EndDate) {
          if (1 == CalcDateDiff(elemval.EndDate, upbound_it->Date)) {
            if (elemval.Flag != 'D') {
              if (elemval.Value == upbound_it->Value) {
                elemval.EndDate = upbound_it->EndDate;
                ++upbound_it;
              }
            }
          }
        } else {  // here split could not be a dot time
          tail_before.Value = split_it->Value;
          FIELDCOPY(tail_before.Code, split_it->Code);
          tail_before.Date = split_it->Date;
          tail_before.EndDate = elemval.EndDate;

          tail_after.Value = split_it->Value;
          FIELDCOPY(tail_after.Code, split_it->Code);
          tail_after.Date = DateAdd(elemval.EndDate, 1);
          tail_after.EndDate = split_it->EndDate;

          objset.erase(split_it);
          objset.insert(tail_before);
          objset.insert(tail_after);
          upbound_it = objset.lower_bound(tail_after);
        }
      }
    }
  }

  try {
    if (lowbound_it != objset.end()) objset.erase(lowbound_it, upbound_it);
  } catch (...) {
  }
  if (elemval.Flag != 'D') objset.insert(elemval);
}

void MacroIndexDict::Dump() {}
void MacroIndexDict::Check() {
  if (!m_benchlog) return;
  typedef MacroIndexManager::MacroIndex MacroIndex;
  typedef MacroIndexManager::DayIndex DayIndex;
  typedef MacroIndexManager::DateType DateType;
  typedef MacroIndexManager::ValueInfo ValueInfo;
  std::vector<MacroIndex*> arrays;
  m_macroindexv2->GetAllArrays(arrays);
  std::vector<ValueInfo> values;
  int nerror = 0;
  int m1 = 0, m2 = 0;
  for (MacroIndexSetMap::iterator it = m_macroindex.begin();
       it != m_macroindex.end(); ++it) {
    m1 += it->second.size() * sizeof(MACRO_INDEX);
  }
  m2 = m_macroindexv2->GetMemoryBytes();
  for (int i = 0; i < (int)arrays.size(); i++) {
    MacroIndex* varray = arrays[i];
    varray->GetValues(values);
    const std::string& name = varray->GetName();
    MacroIndexSetMap::iterator mit = m_macroindex.find(name);
    MacroIndexSet& mset = mit->second;
    if (values.size() != mset.size()) {
      nerror++;
    }
    for (int k = 0; k < (int)values.size(); k++) {
      const ValueInfo& vi = values[k];
      MACRO_INDEX mi = {0};
      mi.Date = vi.start;
      MacroIndexSet::iterator misit = mset.find(mi);
      if (misit != mset.end()) {
        const MACRO_INDEX& exist = *misit;
        if (exist.Value != vi.value || exist.Date != vi.start ||
            exist.EndDate != vi.end) {
          nerror++;
        }

      } else {
        nerror++;
      }
    }
    // DayIndex dayIndex = 0;
    // DateType start, end;
    // double value = 0.0;
    //
    // while (varray->GetValue(dayIndex, value, start, end))
    //{
    //	MACRO_INDEX mi = { 0 };
    //	mi.Date = start;
    //	MacroIndexSet::iterator misit=mset.find(mi);
    //	if (misit != mset.end())
    //	{
    //		const MACRO_INDEX& exist = *misit;
    //		if (exist.Value != value || exist.Date != start || exist.EndDate
    //!= end)
    //		{
    //			BLOGERR("[MACROINDEX]value:%.4f!=%.4f  Date:%d!=%d
    //EndDate:%d!=%d", 				exist.Value, value, exist.Date, start, exist.EndDate, end
    //				);
    //		}

    //	}
    //	else
    //	{
    //		BLOGERR("[MACROINDEX]不存在 name:%s day:%d", name.c_str(),
    //start);
    //	}
    //}
  }
}

int MacroIndexDict::UpdateTable(qb::ht::Table* table, bool sync) {
  // MacroIndexLoader是旧的实现,可能会crash,原因是UpdateMacroElement里面错误使用迭代器破坏
  // m_macroindex的内存结构
  // MacroIndexLoaderV2是新版实现,性能提升10倍,内存为原先的40%
  class MacroIndexLoader : public CBondMacroIndex::ILoader {
    qb::ht::Table* m_table;
    MacroIndexDict* m_macroindex_dict;
    bool m_sync;
    int m_rid;

   public:
    MacroIndexLoader(MacroIndexDict* dict, qb::ht::Table* table, bool sync)
        : m_macroindex_dict(dict), m_table(table), m_sync(sync), m_rid(0) {}
    int GetRid() const { return m_rid; }
    virtual void LoadMacroIndex(CBondMacroIndex* pTarget) {
      MacroIndexDict* dict = m_macroindex_dict;

      int nseq_none_zero = 0;

      int mappos = 0, setpos = 0;
      const MacroIndexDict::MacroIndexSetMap& maps = dict->m_macroindex;
      MacroIndexDict::MacroIndexSetMap::const_iterator mapit = maps.begin();
      for (; mapit != maps.end(); ++mapit, ++mappos) {
        setpos = 0;
        const MacroIndexDict::MacroIndexSet& sets = mapit->second;
        MacroIndexDict::MacroIndexSet::const_iterator setit = sets.begin();
        for (; setit != sets.end(); ++setit, ++setpos) {
          const MACRO_INDEX& bl = *setit;
          Macro_Index_Value stmacro;
          memset(&stmacro, 0, sizeof(stmacro));
          // FIELDCOPY(stmacro.code, bl.Code);
          // COPY_FIELD(Macro_Index, stmacro, code, MACRO_INDEX, bl, Code);
          stmacro.fvalue = bl.Value;
          stmacro.begin_date = bl.Date;
          stmacro.end_date = bl.EndDate;

          qb::ht::DICT_MACRO_INDEX bl2 = {0};
          FIELDCOPY(bl2.Code, bl.Code);
          // COPY_FIELD(DICT_MACRO_INDEX, bl2, Code, MACRO_INDEX, bl, Code);
          bl2.Value = bl.Value;
          bl2.Date = bl.Date;
          bl2.EndDate = bl.EndDate;
          bl2.Flag = bl.Flag == 'D' ? true : false;
          bl2.Sequence = bl.Sequence;
          int keysize = RTL_FIELD_SIZE(qb::ht::DICT_MACRO_INDEX, Key);
          memset(bl2.Key, 0, keysize);
          // StringLinkInt(bl2.Key, _TRUNCATE, bl2.Code, bl2.Date);
          int nret = FMTBUF(bl2.Key, "%s|%d", bl2.Code, bl2.Date);
          m_table->WriteRecordDirect(m_rid++, &bl2, sizeof(bl2));
          if (m_sync) CBondMacroIndex::instance().Add(bl.Code, stmacro);
          if (bl2.Sequence != 0) nseq_none_zero++;
        }
      }
    }
  };
  class MacroIndexLoaderV2 : public CBondMacroIndex::ILoader {
    MacroIndexManager* m_macroindexv2;
    qb::ht::Table* m_table;
    bool m_sync;
    int m_rid;

   public:
    MacroIndexLoaderV2(MacroIndexManager* dict, qb::ht::Table* table, bool sync)
        : m_macroindexv2(dict), m_table(table), m_sync(sync), m_rid(0) {}
    int GetRid() const { return m_rid; }
    virtual void LoadMacroIndex(CBondMacroIndex* pTarget) {
      // CBondMacroIndex的外部已经加锁,见bool CBondMacroIndex::Load(ILoader*
      // loader)
      typedef MacroIndexManager::MacroIndex MacroIndex;
      typedef MacroIndexManager::DayIndex DayIndex;
      typedef MacroIndexManager::DateType DateType;
      typedef MacroIndexManager::ValueInfo ValueInfo;
      std::vector<MacroIndex*> arrays;
      m_macroindexv2->GetAllArrays(arrays);
      std::vector<ValueInfo> values;
      for (int i = 0; i < (int)arrays.size(); i++) {
        MacroIndex* varray = arrays[i];
        varray->GetValues(values);
        const std::string& name = varray->GetName();
        for (int k = 0; k < (int)values.size(); k++) {
          const ValueInfo& vi = values[k];
          qb::ht::DICT_MACRO_INDEX bl2 = {0};
          FIELDCOPY(bl2.Code, name.c_str());
          bl2.Value = vi.value;
          bl2.Date = vi.start;
          bl2.EndDate = vi.end;
          bl2.Sequence =
              0;  // 原始的Sequence到此处理已经全部丢失,忽略此字典的Sequence
          bl2.Flag = 'I';  // 原始的Flag到此处理,已经丢失,写入字典文件的都是更新
          m_table->WriteRecordDirect(m_rid++, &bl2, sizeof(bl2));
          if (m_sync) {
            Macro_Index_Value stmacro;
            memset(&stmacro, 0, sizeof(stmacro));
            stmacro.fvalue = vi.value;
            stmacro.begin_date = vi.start;
            stmacro.end_date = vi.end;
            pTarget->Add(name.c_str(), stmacro);
          }
        }
      }
    }
  };

  if (m_benchlog) {
    Check();
  }
  MacroIndexLoaderV2 loader(m_macroindexv2, table, sync);
  CBondMacroIndex::instance().Load(&loader);
  return loader.GetRid();

  // 旧版本
  // MacroIndexLoader loader(this, table, sync);
  // AfxGetBondMacroIndex().Load(&loader);
  // return loader.GetRid();
}
}  // namespace ht

}  // namespace qb
